//
//  UINavigationController+Transition.swift
//  CustomTransition
//
//  Created by CaryaLiu on 2021/10/14.
//

import UIKit
import RxCocoa
import RxSwift

extension UINavigationController {
    enum TransitionKey {
        static var coordinator: Void?
        static var transition: Void?
    }
    private static let disposeBag = DisposeBag()
    typealias Transitioning = (_ operation: UINavigationController.Operation) -> UIViewControllerAnimatedTransitioning?
    
    var transitionCoordinatorHelper: TransitionCoordinator? {
        get {
            return objc_getAssociatedObject(self, &TransitionKey.coordinator) as? TransitionCoordinator
        }
        set {
            objc_setAssociatedObject(self, &TransitionKey.coordinator, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var transition: [UINavigationController.Operation: TransitionType]? {
        get {
            return objc_getAssociatedObject(self, &TransitionKey.transition) as? [UINavigationController.Operation: TransitionType]
        }
        set {
            return objc_setAssociatedObject(self, &TransitionKey.transition, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
//    func addTransition(enableSwipe: Bool = true, transitioning: @escaping Transitioning) {
//        transitionCoordinatorHelper = TransitionCoordinator()
//        delegate = transitionCoordinatorHelper
//
//        let swipeGestureRecognizer = UISwipeGestureRecognizer()
//        swipeGestureRecognizer.direction = .right
//        swipeGestureRecognizer.rx.event.bind { recognizer in
//
//        }.disposed(by: UINavigationController.disposeBag)
//        view.addGestureRecognizer(swipeGestureRecognizer)
//    }
    
    func addTransition(_ transitionType: TransitionType) {
        transitionCoordinatorHelper = TransitionCoordinator()
        delegate = transitionCoordinatorHelper
        
        let operation = transitionType.operation()
        if var transition = transition {
            transition[operation] = transitionType
            self.transition = transition
        } else {
            transition = [operation: transitionType]
        }
        
        addEdgePan()
//        addSwipe()
    }
    
    private func addSwipe() {
        let swipeGestureRecognizer = UISwipeGestureRecognizer()
        swipeGestureRecognizer.direction = .down
        swipeGestureRecognizer.rx.event.bind { recognizer in
            
            if self.viewControllers.count > 1 {
                self.popViewController(animated: true)
            }
        }.disposed(by: UINavigationController.disposeBag)
        view.addGestureRecognizer(swipeGestureRecognizer)
    }
    
    private func addEdgePan() {
        let swipeGestureRecognizer = UIScreenEdgePanGestureRecognizer()
        swipeGestureRecognizer.edges = .left
        swipeGestureRecognizer.rx.event.bind(onNext: { [weak self] recognizer in
            guard let self = self, let view = recognizer.view else {
                self?.transitionCoordinatorHelper?.interactionController = nil
                return
            }
            let percent = recognizer.translation(in: view).x / view.bounds.width
            if recognizer.state == .began {
                self.transitionCoordinatorHelper?.interactionController = UIPercentDrivenInteractiveTransition()
                self.popViewController(animated: true)
            } else if recognizer.state == .changed {
                self.transitionCoordinatorHelper?.interactionController?.update(percent)
            } else if recognizer.state == .ended || recognizer.state == .cancelled {
                if percent > 0.5 {
                    self.transitionCoordinatorHelper?.interactionController?.finish()
                } else {
                    self.transitionCoordinatorHelper?.interactionController?.cancel()
                }
                self.transitionCoordinatorHelper?.interactionController = nil
            }
        }).disposed(by: UINavigationController.disposeBag)
        view.addGestureRecognizer(swipeGestureRecognizer)
    }
}

class TransitionCoordinator: NSObject, UINavigationControllerDelegate {
    var interactionController: UIPercentDrivenInteractiveTransition?
    
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let transitionType = navigationController.transition?[operation]
        return transitionType?.transitionAnimator()
    }
    
    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return interactionController
    }
}
